﻿using Microsoft.EntityFrameworkCore;
using XYAC.Framework.WohuaMesExtend.IHI.DataContext;
using XYAC.Framework.WohuaMesExtend.IHI.Extensions;
using XYAC.Framework.WohuaMesExtend.IHI.IHI.Models;
using XYAC.Framework.WohuaMesExtend.IHI.Models;

namespace XYAC.Framework.WohuaMesExtend.IHI.Services
{
    /// <summary>
    /// 
    /// 这个类里面有一个问题需要注意：
    /// 数据库上下文，例如AccessIHIDbContext 采用的是注入方式，这个对象会被本类中的方法复用，一旦此类中的多个方法
    /// 被调用时，会导致数据库上下文报出 nullreference 错误。这个问题困扰过前面的程序员。
    /// 今天，在为本应用增加miniWebApi接口实现时，就出现了以上问题；解决办法是使用上下文工厂：
    /// 通过注入IDbContextFactory ，并在每个方法中使用工厂创建上下文进而解决了这个问题，使得程序变得很完美！！！
    /// 20250306注： 也可以更改AccessIHIDbContext注入时的作用域成瞬态的，也可以避免线程争用导致空指针的问题：
    /// 现在本类就是用瞬态注入的方式！
    /// 
    /// </summary>
    public class AccessIHIService
    {
        //private readonly IDbContextFactory<AccessIHIDbContext> _dbAccessContextFactory;

        public AccessIHIService(AccessIHIBaseContext baseDb, AccessIHIDbContext hisDb, IDbContextFactory<AccessIHIDbContext> dbAccessContextFactory)
        {
            this.BaseDb = baseDb;
            this.HisDb = hisDb;
            //_dbAccessContextFactory = dbAccessContextFactory;
        }

        public AccessIHIBaseContext BaseDb { get; }
        public AccessIHIDbContext HisDb { get; }

        internal int Add(SpecInfo_IHI specInfo)
        {
            this.BaseDb.Add(specInfo);
            return this.BaseDb.SaveChanges();
        }

        internal int Update(SpecInfo_IHI specInfo)
        {
            var spec = this.BaseDb.SpecInfo.FirstOrDefault(T => T.ID == specInfo.ID);
            this.BaseDb.Entry(spec).CurrentValues.SetValues(specInfo);
            this.BaseDb.Entry(spec).State = EntityState.Modified;
            return this.BaseDb.SaveChanges();
        }
        internal int AddSpecInfo(SpecInfo_IHI findedRemoteSpec)
        {
            this.BaseDb.SpecInfo.Add(findedRemoteSpec);
            return this.BaseDb.SaveChanges();
        }

        internal DwlData GetLastDwlData()
        {
            try
            {
                //using var db = _dbAccessContextFactory.CreateDbContext();
                //var lst= this.HisDb.DwlData.ToList();
                //var rs = this.HisDb.DwlData.AsNoTracking().OrderByDescending(T => T.DTime).FirstOrDefault(new DwlData());

                var id = HisDb.DwlData.AsNoTracking().Max(x => x.ID);
                var rs = HisDb.DwlData.AsNoTracking().Where(x => x.ID == id).ToList()[0];
                return rs;
            }
            catch (Exception ex)
            {
                return new DwlData();
            }
        }

        internal LaserData GetLastLaserData()
        {
            try
            {
                //using var db = _dbAccessContextFactory.CreateDbContext();
                //var lst = this.HisDb.LaserData.ToList();
                var id= HisDb.LaserData.AsNoTracking().Max(x => x.ID);
                var rs = HisDb.LaserData.AsNoTracking().Where(x => x.ID == id).ToList()[0];
                //var rs = HisDb.LaserData.AsNoTracking().OrderByDescending(T => T.DTime).FirstOrDefault(new LaserData());
                return rs;
            }
            catch (Exception ex)
            {
                return new LaserData();
            }
        }

        internal object GetSpecInfoById(int iD)
        {
            return this.BaseDb.SpecInfo.FirstOrDefault(T => T.ID == iD);
        }

        internal IList<SpecInfo_IHI> GetSpecInfos()
        {
            var x = this.BaseDb.SpecInfo.ToList();
            CrcCalculator calculator = new CrcCalculator();
            x.ForEach(T => T.Hash = calculator.ComputeCrc128(JsonSerializeHelper.SerializeObjectToJson(T)).ToString());
            return x;
        }

        internal int RemoveViaSpecNames(IEnumerable<string> preRemoveSpecKey)
        {
            var specinfos = this.BaseDb.SpecInfo.Where(T => preRemoveSpecKey.Contains(T.TypeName));
            this.BaseDb.SpecInfo.RemoveRange(specinfos);
            return this.BaseDb.SaveChanges();
        }

        internal bool SaveRemoteSpecInfoToLocal(SpecInfo_IHI findedRemoteSpec)
        {
            var entity = BaseDb.SpecInfo.FirstOrDefault(T => T.TypeName == findedRemoteSpec.TypeName);
            BaseDb.Entry(entity).CurrentValues.SetValues(findedRemoteSpec);
            BaseDb.Entry(entity).State = EntityState.Modified;
            var ret = BaseDb.SaveChanges() > 0;
            return ret;
        }

        internal List<SpecInfo_IHI> GetAllSpecInfo()
        {
            var calc = new CrcCalculator();
            var specinfos = this.BaseDb.SpecInfo.ToList();
            specinfos.ForEach(T =>
            {
                T.Hash = calc.ComputeCrc128(JsonSerializeHelper.SerializeObjectToJson(T)).ToString();
            });
            return specinfos;
        }
    }
}
